package interfaces;

import java.awt.Checkbox;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import algorithms.HuffmanTree;
import algorithms.Record;

public class MainWindow extends Thread {

	private JFrame frame = new JFrame();
	HuffmanTree tree = null;

	public MainWindow() throws IOException {
		frame.setBounds(100, 100, 500, 98);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().setLayout(null);
		frame.setResizable(false);

		final JTextField textField = new JTextField();
		textField.setBounds(10, 10, 335, 22);
		frame.getContentPane().add(textField);

		final JButton button = new JButton("Encode/Decode");
		button.setBounds(355, 38, 129, 22);
		frame.getContentPane().add(button);

		final JButton chooseFileButton = new JButton("Browse...");
		chooseFileButton.setBounds(355, 10, 129, 22);
		frame.getContentPane().add(chooseFileButton);

		final Checkbox checkbox = new Checkbox("Step by step");
		checkbox.setBounds(10, 38, 95, 22);
		frame.getContentPane().add(checkbox);
		checkbox.setVisible(false);

		// Text field edit listener
		textField.getDocument().addDocumentListener(new DocumentListener() {
			private void setCheckboxVisibility() {
				if (getFilenameExtention(textField.getText()).equals("txt"))
					checkbox.setVisible(true);
				else
					checkbox.setVisible(false);
			}

			public void insertUpdate(DocumentEvent arg0) {
				setCheckboxVisibility();
			}

			public void changedUpdate(DocumentEvent arg0) {
				setCheckboxVisibility();
			}

			public void removeUpdate(DocumentEvent arg0) {
				setCheckboxVisibility();
			}
		});

		// File chooser listener
		chooseFileButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				JFileChooser chooser = new JFileChooser();
				chooser.setCurrentDirectory(new File("."));
				chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
				int result = chooser.showOpenDialog(null);
				if (result == JFileChooser.APPROVE_OPTION) {
					File file = chooser.getSelectedFile();
					textField.setText(file.getPath());
				}
				button.requestFocus();
			}
		});

		// Encode button listener
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				String extention = getFilenameExtention(textField.getText());
				if (extention.equals("txt")) {
					try {
						File file = new File(textField.getText());
						textField.setText(file.getAbsolutePath());
						file = new File(textField.getText());
						file.getParentFile().mkdirs();
						encodeFile(file, checkbox.getState());
					} catch (IOException e) {
						JOptionPane.showMessageDialog(frame, "File not found");
					}
				} else if (extention.equals("ktc")) {
					try {
						File file = new File(textField.getText());
						textField.setText(file.getAbsolutePath());
						file = new File(textField.getText());
						file.getParentFile().mkdirs();
						decodeFile(file);
					} catch (IOException e) {
						JOptionPane.showMessageDialog(frame, "File not found");
					}
				} else if (extention.isEmpty())
					JOptionPane.showMessageDialog(frame, "Empty field");
				else
					JOptionPane.showMessageDialog(frame, "Wrong file format");
			}
		});

	}

	public static void main(String[] args) throws IOException {
		MainWindow window = new MainWindow();
		window.frame.setVisible(true);
	}

	private void paint() {
		Graphics g = frame.getGraphics();
		g.setColor(Color.white);
		int width = (int) Toolkit.getDefaultToolkit().getScreenSize()
				.getWidth();
		int height = (int) Toolkit.getDefaultToolkit().getScreenSize()
				.getHeight();
		g.fillRect(0, 0, width, height);
		g.setColor(Color.black);
		if (tree != null)
			tree.printTree(frame, 50);
	}

	private void encodeFile(File file, boolean stepByStep) throws IOException {

		// Create tree
		tree = new HuffmanTree();

		// Generate new filename
		String outputFileName = file.getAbsolutePath();
		while (outputFileName.charAt(outputFileName.length() - 1) != '.')
			outputFileName = outputFileName.substring(0,
					outputFileName.length() - 1);
		outputFileName += "ktc";
		File outputFile = new File(outputFileName);

		// Tree output window
		if (stepByStep) {
			for (Component component : frame.getComponents()) {
				component.setVisible(false);
			}
			int width = (int) Toolkit.getDefaultToolkit().getScreenSize()
					.getWidth();
			int height = (int) Toolkit.getDefaultToolkit().getScreenSize()
					.getHeight();
			frame.setBounds(0, 0, width, height);
		}
		Record rec = new Record(outputFile, true);
		BufferedReader br = new BufferedReader(new FileReader(file));
		int symbol = '\0';
		symbol = br.read();
		while (symbol != -1) {
			char c = (char) symbol;
			rec.add(tree.getCharCode(c), false);
			if (c == '0')
				c = (char) 18;
			if (c == '1')
				c = (char) 16;
			tree.add(c);
			if (stepByStep) {
				paint();
				try {
					Thread.sleep(499);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			symbol = br.read();
		}
		rec.add("", true);
		br.close();
		if (stepByStep) {
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			for (Component component : frame.getComponents()) {
				component.setVisible(true);
			}
			frame.setBounds(100, 100, 500, 98);
		} else
			JOptionPane.showMessageDialog(frame, "Encoding finished");
	}

	private String getFilenameExtention(String filename) {
		if (filename.isEmpty())
			return new String();
		String ext = new String();
		int i = filename.length() - 1;
		while (filename.charAt(i) != '.') {
			ext = filename.charAt(i) + ext;
			i--;
			if (i < 0)
				return new String("Wrong");
		}
		return ext;
	}

	private void decodeFile(File file) throws IOException {
		Record record = new Record(file, false);
		record.decodeToHuffman(file);

		// Generate tmp file name
		String tmpFileName = file.getAbsolutePath();
		while (tmpFileName.charAt(tmpFileName.length() - 1) != '.')
			tmpFileName = tmpFileName.substring(0, tmpFileName.length() - 1);
		tmpFileName += "tmp";
		File tmpFile = new File(tmpFileName);
		FileInputStream in = new FileInputStream(tmpFile);

		// Generate txt file name
		String decodedFileName = file.getAbsolutePath();
		while (decodedFileName.charAt(decodedFileName.length() - 1) != '.')
			decodedFileName = decodedFileName.substring(0,
					decodedFileName.length() - 1);
		decodedFileName += "txt";
		File decodedFile = new File(decodedFileName);

		FileOutputStream out = new FileOutputStream(decodedFile);
		HuffmanTree tree = new HuffmanTree();
		HuffmanTree.Node tempNode;
		String codeOfChar = new String();
		char temp = (char) in.read();
		do {
			if (!codeOfChar.isEmpty()) {
				tempNode = tree.getCharByCode(codeOfChar);
				if (tempNode != null) {
					if (tempNode == tree.getNullNode())
						temp = (char) in.read();
					else
						temp = tempNode.getCharacter();
					if (temp == (char) 16)
						temp = '1';
					if (temp == (char) 18)
						temp = '0';
					tree.add(temp);
					out.write(temp);
					temp = (char) in.read();
					codeOfChar = "";
					continue;
				}
				temp = (char) in.read();
			}
			if (temp == '0' | temp == '1')
				codeOfChar += temp;
			else {
				if (temp == (char) 16)
					temp = '1';
				if (temp == (char) 18)
					temp = '0';
				out.write(temp);
				tree.add(temp);
				codeOfChar = "";
				temp = (char) in.read();
			}
		} while (temp != (char) -1);
		out.close();
		in.close();
		tmpFile.delete();
		JOptionPane.showMessageDialog(frame, "Decoding finished");
	}

}
